//package com.yupi.project.filters;
//
///**
// * @ClassName TestFilter
// * @Description TODO
// * @Author zzsource
// * @Date 2023/10/21 4:36
// * @Version 1.0
// **/
//
//import cn.hutool.core.bean.BeanUtil;
//import cn.hutool.json.JSONUtil;
//import com.yupi.project.manager.RedisLimiterManager;
//import com.yupi.yuapicommon.model.common.BusinessException;
//import com.yupi.yuapicommon.model.common.ErrorCode;
//import com.yupi.yuapicommon.model.entity.InterfaceInfo;
//import com.yupi.yuapicommon.model.entity.User;
//import com.yupi.yuapicommon.service.InnerInterfaceInfoService;
//import com.yupi.yuapicommon.service.InnerUserService;
//import lombok.extern.slf4j.Slf4j;
//import org.apache.dubbo.config.annotation.DubboReference;
//import org.springframework.cloud.gateway.filter.GatewayFilterChain;
//import org.springframework.cloud.gateway.filter.GlobalFilter;
//import org.springframework.core.Ordered;
//import org.springframework.core.io.ClassPathResource;
//import org.springframework.data.redis.core.StringRedisTemplate;
//import org.springframework.data.redis.core.script.DefaultRedisScript;
//import org.springframework.http.HttpHeaders;
//import org.springframework.http.HttpStatus;
//import org.springframework.http.server.reactive.ServerHttpRequest;
//import org.springframework.http.server.reactive.ServerHttpResponse;
//import org.springframework.stereotype.Component;
//import org.springframework.web.server.ServerWebExchange;
//import reactor.core.publisher.Mono;
//
//import javax.annotation.Resource;
//import java.util.Collections;
//import java.util.function.Consumer;
//
//import static com.yupi.project.model.RedisConstants.REQUEST_NONCE_KEY;
//import static com.yupi.project.model.RedisConstants.REQUEST_NONCE_TTL;
//
//@Slf4j(topic = "RedisFilter")
//@Component
//public class RedisFilter implements GlobalFilter, Ordered {
//
//    @Resource
//    private StringRedisTemplate stringRedisTemplate;
//
//    @Resource
//    private RedisLimiterManager redisLimiterManager;
//
//    @DubboReference
//    private InnerUserService innerUserService;
//
//    @DubboReference
//    private InnerInterfaceInfoService innerInterfaceInfoService;
//
//    private static final String KEY_PREFIX = "interface:invoke:";
//
//    private static final String INTERFACE_HOST = "http://localhost:8123";
//
//    private static final DefaultRedisScript<Long> SECKILL_SCRIPT;
//
//    static {
//        SECKILL_SCRIPT = new DefaultRedisScript<>();
//        SECKILL_SCRIPT.setLocation(new ClassPathResource("nonce.lua"));
//        SECKILL_SCRIPT.setResultType(Long.class);
//    }
//
//    @Override
//    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//        ServerHttpRequest request = exchange.getRequest();
//        ServerHttpResponse response = exchange.getResponse();
//        HttpHeaders headers = request.getHeaders();
//        String nonce = headers.getFirst("nonce");
//        String accessKey = headers.getFirst("accessKey");
//        String path = request.getURI().toString();
//        String method = request.getMethod().name();
//
//        //用户账号数据库查询
//        User invokeUser = null;
//        try {
//            invokeUser = innerUserService.getInvokeUser(accessKey);
//        }catch (Exception e){
//            log.error("getinvokeUser error", e);
//        }
//        if(invokeUser == null){
//            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "请求用户不存在");
//        }
//
//        // 请求的模拟接口是否存在?
//        //从数据库中查询模拟接口是否存在，以及请求方法是否匹配（还可以校验参数）
//        InterfaceInfo interfaceInfo = null;
//        try {
//            int index = path.indexOf("?");
//            interfaceInfo = innerInterfaceInfoService.getInterfaceInfo(path.substring(0,  index == -1 ? path.length() : index), method);
//        } catch (Exception e){
//            log.error("getInterfaceInfo error", e);
//        }
//        if(interfaceInfo == null){
//            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "第三方接口不存在");
//        }
//
//        // 随机数，防止请求重放
//        if(nonce == null || Long.parseLong(nonce) > 1000000L){
//            return handleNoAuth(response);
//        }else {// 检验是否重放
//            String key = REQUEST_NONCE_KEY + "ak_" + headers.get("accessKey") + ":path_" + request.getPath().value();
//            Long isAlive = stringRedisTemplate.execute(
//                    SECKILL_SCRIPT,
//                    Collections.emptyList(),
//                    key, REQUEST_NONCE_TTL.toString(), nonce
//            );
//            if(isAlive == 0){// 0，说明已经存在该值，说明重放了，拒绝请求
//                return handleNoAuth(response);
//            }
//        }
//
//        // 接口限流，限制用户在接口上的调用频率。默认是单个用户1秒至多调用5次
//        String key = KEY_PREFIX + invokeUser.getId() + ":" + interfaceInfo.getId();
//        Integer rate = interfaceInfo.getRate();
//        Integer rateInterval = interfaceInfo.getRateInterval();
//        Integer rateIntervalUnit = interfaceInfo.getRateIntervalUnit();
//        try {
//            redisLimiterManager.doRateLimit(key, rate, rateInterval, rateIntervalUnit);
//        } catch (Exception e){
//            log.error("调用过于频繁，稍后重试");
//            return handleInvokeError(response);
//        }
//        return chain.filter(exchange);
//    }
//
//    private Mono<Void> handleServiceUnavailable(ServerHttpResponse response){
//        response.setStatusCode(HttpStatus.SERVICE_UNAVAILABLE);
//        return response.setComplete();
//    }
//
//    private Mono<Void> handleNoAuth(ServerHttpResponse response){
//        response.setStatusCode(HttpStatus.FORBIDDEN);
//        return response.setComplete();
//    }
//
//    private Mono<Void> handleInvokeError(ServerHttpResponse response){
//        response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
//        return response.setComplete();
//    }
//
//    @Override
//    public int getOrder() {
//        return -10;
//    }
//}
//
